﻿using System;
using SqlLibrary;
using System.Collections;
using System.Web.UI.WebControls;
using System.Reflection;
using Ecopsy.DataTier;
using Ecopsy.DataTier.SqlLibrary;



namespace SqlLibrary
{
    /// <summary>
    /// Summary description for ListWhere
    /// </summary>
    public class ListWhere : EntitySingle
    {
        //условия сортировки
        private TSortCondition _SortCondition = new TSortCondition();
        public TSortCondition SortCondition { get { return _SortCondition; } set { _SortCondition = value; } }

        /// <summary>
        /// Инструемнт позволяющий сравнить 2 объекта с помощью передаваемой ему функции
        /// </summary>
        public class TSortCondition : EntitySingle, IComparer
        {
            public SortDirection SortDirection { get; set; }
            public string SortField { get; set; }

            #region IComparer Members

            public Func<TSortCondition, object, object, int> fnOrderBy { get; set; }
            public int Compare(object x, object y)
            {
                return fnOrderBy(this, x, y); ;

            }

            #endregion
        }

        /// <summary>
        /// sql запрос - отбирающий список
        /// </summary>
        public ListLoadStatment ListLoadStatment { get; set; }


    }

    /// <summary>
    /// часто используемые алгоритмы сортировки - универсальныые для полей и объектов
    /// </summary>
    public static class SortFunctions
    {
        /// <summary>
        /// Фнкция сортирующая объекты по полю азаданному в SortCond.SortField 
        /// </summary>
        public static Func<ListWhere.TSortCondition, object, object, int> fOrderBy = delegate(ListWhere.TSortCondition SortCond, object x, object y)
        {
            // еси ссылка на один объект - объекты равны
            if (x == y) return 0;

            object vx = GetFieldValue(x, SortCond.SortField);
            object vy = GetFieldValue(y, SortCond.SortField);

            if (null == vx) return -1;
            if (null == vy) return 1;

            int r = 0;
            switch (GetPropertyTypeCode(x, SortCond.SortField))
            {
                case 0:
                    r = vx.ToString().ToUpper().CompareTo(vy.ToString().ToUpper());
                    break;
                case 1:
                    r = (Convert.ToInt32(vx)).CompareTo(Convert.ToInt32(vy));
                    break;

                case 2:
                    r = (Convert.ToDateTime (vx)).CompareTo(Convert.ToDateTime (vy));
                    break;    
                
            }

           if (0 == r) return r;
           if (SortCond.SortDirection == SortDirection.Ascending) return r;
            return (r > 0 ? -1 : 1);

        };


        /// <summary>
        /// Вернуть код типа свойства
        /// 0-string
        /// 1-int|decimal и т.д.
        /// 2-datatime
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private static int GetPropertyTypeCode(object x, string FieldName)
        {
            Type t = x.GetType();
            PropertyInfo p = t.GetProperty(FieldName);
            
            if (p.PropertyType.Name.ToUpper().IndexOf("String".ToUpper()) > -1)
                return 0;

            if (p.PropertyType.Name.ToUpper().IndexOf("DateTime".ToUpper()) > -1)
                return 2;

            return 1;

        }
        

        private static object GetFieldValue(object Context, string FieldName)
        {
            try
            {
                Type t = Context.GetType();
                PropertyInfo p = t.GetProperty(FieldName);
                
                return p.GetValue(Context, null); ;
            }
            catch
            {
                return null;
            }
        }


    }
}